package com.ygqh.baby.handler;

import com.foxinmy.weixin4j.util.StringUtil;
import com.ygqh.baby.ao.*;
import com.ygqh.baby.model.*;
import com.ygqh.baby.po.*;
import com.ygqh.baby.service.*;
import com.ygqh.baby.utils.DateConvertUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 〈退款金额处理器〉
 *
 * @author guohao
 * @date 2018/12/14 10:01
 * @since 1.0.0
 */
@Component
public class ReturnPriceHandler {

    @Autowired
    private YgReturnOrderService ygReturnOrderService;
    @Autowired
    private YgOrderDetailService ygOrderDetailService;
    @Autowired
    private YgReturnOrderDetailService ygReturnOrderDetailService;
    @Autowired
    private YgOrderService ygOrderService;
    @Autowired
    private YgSkuService ygSkuService;
    @Autowired
    private YgCouponDetailService ygCouponDetailService;
    @Autowired
    private CalculateReturnPriceHandler calculateReturnPriceHandler;


    public Message getReturnPrice(YgReturnInfoModel returnInfo) {

        Long orderId = returnInfo.getOrderId();
        YgOrder order = ygOrderService.findByOrderId(orderId);
        //新订单走新逻辑
        Date parse = DateConvertUtils.parse("2019-05-16 10:00:00", DateConvertUtils.DATE_TIME_FORMAT);
        if (order.getCreateTime().after(parse)) {
            return calculateReturnPriceHandler.getReturnPrice(returnInfo);
        }
        OrderReturnedInfo orderReturnedInfo = this.getOrderReturnedInfo(orderId);
        orderReturnedInfo.setManJianPrice(order.getManjianPrice());
        orderReturnedInfo.setCouponPrice(order.getYouhuijuanPrice());
        orderReturnedInfo.setTotalPrice(order.getTotalPrice());
        orderReturnedInfo.setAccountPrice(order.getAccountPrice());
        BigDecimal orderPrice = order.getProductPrice().subtract(order.getPackDisPrice()).subtract(order.getNewCustomDisPrice()).subtract(order
                .getGroupDisPrice()).subtract(order.getBmdisPrice()).add(order.getExpressPrice());
        orderReturnedInfo.setOrderPrice(orderPrice);

        BigDecimal specialPrice = BigDecimal.ZERO;
        if (StringUtil.isNotBlank(order.getExpressCompany())) {
            specialPrice = new BigDecimal(order.getExpressCompany());
        }
        orderReturnedInfo.setExcludedSpecialPrice(orderPrice.subtract(specialPrice));
        // 优惠券作用域
        setCouponScope(orderReturnedInfo, order);
        //处理历史订单退货 上线时放开
        if (order.getCreateTime().before(Objects.requireNonNull(DateConvertUtils.parse("2018-12-24", DateConvertUtils.DATE_FORMAT)))) {
            return doGetReturnPriceByOld(returnInfo, orderReturnedInfo);
        }
        return doGetReturnPrice(returnInfo, orderReturnedInfo);
    }

    private Message doGetReturnPriceByOld(YgReturnInfoModel returnInfo, OrderReturnedInfo orderReturnedInfo) {
        Message oldMsg = ygReturnOrderService.getReturnPrice(returnInfo);
        if (oldMsg.getType().equals(Message.Type.error)) {
            return oldMsg;
        }
        YgReturnInfoModel info = (YgReturnInfoModel) oldMsg.getExtra();
        ReturnPriceModel returnPriceModel = getReturnPriceModel(info.getReturnPrice(), orderReturnedInfo);
        info.setReturnPriceModel(returnPriceModel);
        oldMsg.setExtra(info);
        return oldMsg;
    }

    private Message doGetReturnPrice(YgReturnInfoModel returnInfo, OrderReturnedInfo orderReturnedInfo) {
        List<OrderDetailWithReturnInfo> detailList = orderReturnedInfo.getDetailList();
        List<ReturnSkuInfo> skuInfos = returnInfo.getSkuInfos();
        for (OrderDetailWithReturnInfo detailWithReturnInfo : detailList) {
            for (ReturnSkuInfo skuInfo : skuInfos) {
                if (skuInfo.getSkuId().equals(detailWithReturnInfo.getSkuId())) {
                    if (skuInfo.getQuantity().compareTo(detailWithReturnInfo.getLastCount()) > 0) {
                        return Message.error("退货数量多于可退数量。" + skuInfo.getSkuId());
                    }
                    detailWithReturnInfo.setThisReturnCount(skuInfo.getQuantity());
                }

            }
        }

        BigDecimal returnPrice = BigDecimal.ZERO;

        //支付金额 + 成长金
        BigDecimal orderPrice = orderReturnedInfo.getOrderPrice();
        BigDecimal manJianPrice = orderReturnedInfo.getManJianPrice();
        BigDecimal couponPrice = orderReturnedInfo.getCouponPrice();
        BigDecimal excludedSpecialPrice = orderReturnedInfo.getExcludedSpecialPrice();
        for (OrderDetailWithReturnInfo detail : detailList) {
            BigDecimal detailReturnPrice = BigDecimal.ZERO;
            if (detail.getLastCount() > 0) {
                detailReturnPrice = getDetailReturnPrice(detail, orderPrice, excludedSpecialPrice, manJianPrice, couponPrice);
                returnPrice = returnPrice.add(detailReturnPrice);
            }

            for (ReturnSkuInfo skuInfo : skuInfos) {
                if (skuInfo.getSkuId().equals(detail.getSkuId())) {
                    skuInfo.setPrice(detailReturnPrice);
                }
            }
        }
        long count = detailList.stream().filter(item -> item.getThisReturnCount().compareTo(item.getLastCount()) < 0).count();
        BigDecimal refundAblePrice = orderReturnedInfo.getTotalPrice().add(orderReturnedInfo.getAccountPrice())
                .subtract(orderReturnedInfo.getTotalRefundedPrice()).subtract(orderReturnedInfo.getTotalRefundedAccountPrice());
        if (count == 0 || returnPrice.compareTo(refundAblePrice) > 0) {
            returnPrice = refundAblePrice;
        }

        ReturnPriceModel returnPriceModel = getReturnPriceModel(returnPrice, orderReturnedInfo);

        BigDecimal returnProductPrice = returnPriceModel.getReturnProductPrice();

        BigDecimal lastPrice = returnProductPrice;
        for (int i = 0; i < skuInfos.size(); i++) {
            ReturnSkuInfo returnSkuInfo = skuInfos.get(i);
            BigDecimal price = returnSkuInfo.getPrice();
            if (i == skuInfos.size() - 1) {
                price = lastPrice;
            }
            BigDecimal skuCount = new BigDecimal(returnSkuInfo.getQuantity());
            BigDecimal multiply = returnProductPrice.divide(returnPrice, 2, BigDecimal.ROUND_DOWN).multiply(price);
            BigDecimal divide = multiply.divide(skuCount, 2, BigDecimal.ROUND_DOWN);
            returnSkuInfo.setPrice(divide);
            lastPrice = lastPrice.subtract(divide.multiply(skuCount));
        }

        //兼容其他接口 需返回 YgReturnInfoModel 重构时可优化
        returnInfo.setReturnPrice(returnPrice);
        returnInfo.setReturnPriceModel(returnPriceModel);
        //你考虑运费
        returnInfo.setExpressPrice(BigDecimal.ZERO);
        return Message.success(returnInfo);

    }

    private ReturnPriceModel getReturnPriceModel(BigDecimal returnPrice, OrderReturnedInfo orderReturnedInfo) {
        BigDecimal lastTotalPrice = orderReturnedInfo.getTotalPrice().subtract(orderReturnedInfo.getTotalRefundedPrice());
        BigDecimal lastAccountPrice = orderReturnedInfo.getAccountPrice().subtract(orderReturnedInfo.getTotalRefundedAccountPrice());

        BigDecimal returnAccountPrice = returnPrice.subtract(lastTotalPrice);
        BigDecimal returnProductPrice;

        ReturnPriceModel returnPriceModel = new ReturnPriceModel();
        // 退款金额大于剩余 实付金额,且剩余成长金额不足
        if (returnAccountPrice.compareTo(BigDecimal.ZERO) > 0
                && returnAccountPrice.compareTo(lastAccountPrice) > 0) {
            returnAccountPrice = lastAccountPrice;
        } else if (returnAccountPrice.compareTo(BigDecimal.ZERO) < 0) {
            returnAccountPrice = BigDecimal.ZERO;
        }
        returnProductPrice = returnPrice.subtract(returnAccountPrice);
        returnPriceModel.setReturnPrice(returnPrice);
        returnPriceModel.setReturnProductPrice(returnProductPrice);
        returnPriceModel.setReturnAccountPrice(returnAccountPrice);
        return returnPriceModel;
    }

    private BigDecimal getDetailReturnPrice(OrderDetailWithReturnInfo detail, BigDecimal orderPrice, BigDecimal excludedSpecialPrice,
                                            BigDecimal manjianPrice, BigDecimal couponPrice) {
        if (detail.getThisReturnCount() == 0) {
            return BigDecimal.ZERO;
        }
        if (detail.getSpecial()) {
            couponPrice = BigDecimal.ZERO;
        }
        if (detail.getPromotionType().equals(PromotionType.Pack)) {
            //参与新客的件数
            Long newCustomCount = 0L;
            //参与自选包的件数
            Long packQuantity = detail.getPackQuantity();
            //有一件参与新客价
            if (detail.getNewCustomPrice().compareTo(BigDecimal.ZERO) > 0) {
                newCustomCount = 1L;
            }
            //正常售卖的件数
            Long ordinaryCount = detail.getBuyCount() - packQuantity - newCustomCount;
            //剩余正常售卖可退件数
            ordinaryCount = ordinaryCount - detail.getReturnedCount();
            if (ordinaryCount < 0) {
                newCustomCount = newCustomCount + ordinaryCount;
                ordinaryCount = 0L;
                if (newCustomCount < 0) {
                    packQuantity = newCustomCount + packQuantity;
                    newCustomCount = 0L;
                    if (packQuantity < 0) {
                        throw new RuntimeException("获取退款金额异常。已超数量退货。orderId: " + detail.getOrderId() + " skuId:" + detail.getSkuId());
                    }
                }
            }
            BigDecimal detailReturnPrice = BigDecimal.ZERO;

            Long thisOrdinaryReturnCount;
            Long thisNewCustomReturnCount = 0L;
            Long thisPackReturnCount = 0L;
            Long thisReturnCount = detail.getThisReturnCount();
            Long thisLastReturnCount = thisReturnCount - ordinaryCount;
            if (thisLastReturnCount > 0) {
                thisOrdinaryReturnCount = ordinaryCount;
                thisLastReturnCount = thisLastReturnCount - newCustomCount;
                if (thisLastReturnCount > 0) {
                    thisNewCustomReturnCount = newCustomCount;
                    thisPackReturnCount = thisLastReturnCount;
                    thisLastReturnCount = thisLastReturnCount - packQuantity;
                    if (thisLastReturnCount > 0) {
                        throw new RuntimeException("获取退款金额异常。超数量退货。orderId: " + detail.getOrderId() + " skuId:" + detail.getSkuId());
                    }
                } else {
                    thisNewCustomReturnCount = thisLastReturnCount;
                }
            } else {
                thisOrdinaryReturnCount = thisReturnCount;
            }

            if (thisOrdinaryReturnCount > 0) {
                BigDecimal price = getRealSalePrice(orderPrice, excludedSpecialPrice, manjianPrice, couponPrice, detail.getSalePrice());
                BigDecimal ordinaryPrice = price.multiply(new BigDecimal(thisOrdinaryReturnCount));
                detailReturnPrice = detailReturnPrice.add(ordinaryPrice);
            }
            if (thisNewCustomReturnCount > 0) {
                BigDecimal price = getRealSalePrice(orderPrice, excludedSpecialPrice, manjianPrice, couponPrice, detail.getNewCustomPrice());
                BigDecimal ordinaryPrice = price.multiply(new BigDecimal(thisNewCustomReturnCount));
                detailReturnPrice = detailReturnPrice.add(ordinaryPrice);
            }
            if (thisPackReturnCount > 0) {
                couponPrice = detail.getPackUseCoupon() ? couponPrice : BigDecimal.ZERO;
                BigDecimal packSharePrice = detail.getPackPrice().divide(new BigDecimal(detail.getProductAmount()), 2, BigDecimal.ROUND_HALF_UP);
                BigDecimal price = getRealSalePrice(orderPrice, excludedSpecialPrice, manjianPrice, couponPrice, packSharePrice);
                BigDecimal ordinaryPrice = price.multiply(new BigDecimal(thisPackReturnCount));
                detailReturnPrice = detailReturnPrice.add(ordinaryPrice);
            }
            return detailReturnPrice;
        } else if (detail.getPromotionType().equals(PromotionType.NewCustom) && detail.getReturnedCount() == 0) {
            BigDecimal newCustomPrice = getRealSalePrice(orderPrice, excludedSpecialPrice, manjianPrice, couponPrice, detail.getNewCustomPrice());
            BigDecimal ordinaryPrice = getRealSalePrice(orderPrice, excludedSpecialPrice, manjianPrice, couponPrice, detail.getSalePrice());
            return newCustomPrice.add(ordinaryPrice.multiply(new BigDecimal(detail.getReturnedCount() - 1)));
        }
        BigDecimal price = getRealSalePrice(orderPrice, excludedSpecialPrice, manjianPrice, couponPrice, detail.getSalePrice());
        return price.multiply(new BigDecimal(detail.getThisReturnCount()));

    }

    /**
     * 减去满减、优惠券 优惠后的 售价
     *
     * @return BigDecimal
     */
    private BigDecimal getRealSalePrice(BigDecimal orderPrice, BigDecimal excludedSpecialPrice, BigDecimal manjianPrice, BigDecimal couponPrice, BigDecimal salePrice) {
        BigDecimal disManJianPrice = this.getDisManJianPrice(manjianPrice, orderPrice, salePrice);
        BigDecimal disCouponPrice = this.getDisYouHuiQuanPrce(couponPrice, excludedSpecialPrice, salePrice);
        return salePrice.subtract(disManJianPrice).subtract(disCouponPrice);
    }

    private OrderReturnedInfo getOrderReturnedInfo(Long orderId) {
        List<YgReturnOrder> returnList = ygReturnOrderService.findByOrderIdList(Collections.singletonList(orderId), ReturnType.Return);
        List<YgReturnOrder> returnedList = returnList.stream().filter(ro -> ro.getReturnStatus().equals(ReturnStatus.Complete)).collect(Collectors.toList());

        List<String> returnCodeList = returnedList.stream().map(YgReturnOrder::getReturnCode).collect(Collectors.toList());
        List<YgReturnOrderDetail> returnDetailList = ygReturnOrderDetailService.findByReturnCodeList(returnCodeList);
        return setOrderDetailReturnedInfo(orderId, returnedList, returnDetailList);
    }

    private OrderReturnedInfo setOrderDetailReturnedInfo(Long orderId, List<YgReturnOrder> returnedList, List<YgReturnOrderDetail> returnDetailList) {


        List<OrderDetailWithReturnInfo> orderDetailPromotionInfoList = this.getOrderDetailPromotionInfoList(orderId);
        BigDecimal refundedPrice = BigDecimal.ZERO;
        BigDecimal refundedAccountPrice = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(returnedList)) {
            for (YgReturnOrder returnOrder : returnedList) {
                refundedPrice = refundedPrice.add(returnOrder.getRefundPrice());
                refundedAccountPrice = refundedAccountPrice.add(returnOrder.getRefundAccountPrice());
            }

            Map<Long, List<YgReturnOrderDetail>> detailMap = returnDetailList.stream().collect(Collectors.groupingBy(YgReturnOrderDetail::getSourceSkuId));

            for (OrderDetailWithReturnInfo detailWithReturnInfo : orderDetailPromotionInfoList) {
                List<YgReturnOrderDetail> returnOrderDetailList = detailMap.get(detailWithReturnInfo.getSkuId());
                if (CollectionUtils.isNotEmpty(returnOrderDetailList)) {
                    Long returnedCount = returnOrderDetailList.stream().map(YgReturnOrderDetail::getAmount).reduce(0L, (a, b) -> (a + b));
                    detailWithReturnInfo.setReturnedCount(returnedCount);
                }

            }
        }
        OrderReturnedInfo orderReturnedInfo = new OrderReturnedInfo();
        orderReturnedInfo.setOrderId(orderId);
        orderReturnedInfo.setTotalRefundedPrice(refundedPrice);
        orderReturnedInfo.setTotalRefundedAccountPrice(refundedAccountPrice);
        orderReturnedInfo.setDetailList(orderDetailPromotionInfoList);

        return orderReturnedInfo;

    }

    private List<OrderDetailWithReturnInfo> getOrderDetailPromotionInfoList(Long orderId) {
        List<YgOrderDetail> odList = ygOrderDetailService.findByOrderId(orderId);
        return this.doGetOrderDetailPromotionInfoList(odList);
    }

    private List<OrderDetailWithReturnInfo> doGetOrderDetailPromotionInfoList(List<YgOrderDetail> odList) {

        List<OrderDetailWithReturnInfo> list = new ArrayList<>(odList.size());
        for (YgOrderDetail orderDetail : odList) {
            OrderDetailWithReturnInfo orderDetailPromotionInfo = new OrderDetailWithReturnInfo();
            PromotionType detailPromotion = getDetailPromotion(orderDetail);
            orderDetailPromotionInfo.setOrderId(orderDetail.getOrderId());
            orderDetailPromotionInfo.setDetailId(orderDetail.getId());
            orderDetailPromotionInfo.setSkuId(orderDetail.getSkuId());
            orderDetailPromotionInfo.setBuyCount(orderDetail.getQuantity());
            orderDetailPromotionInfo.setPromotionType(detailPromotion);
            orderDetailPromotionInfo.setSalePrice(orderDetail.getSalePrice());
            orderDetailPromotionInfo.setSpecial(orderDetail.getPromotionType().equals(PromotionType.IsSpecial));
            String remark = orderDetail.getRemark();

            String[] split = new String[]{"0"};
            if (StringUtil.isNotBlank(remark)) {
                split = remark.split(",");
            }
            switch (detailPromotion) {
                case NewCustom:
                    //NewCustom,newCustomPrice
                    orderDetailPromotionInfo.setSalePrice(new BigDecimal(split[1]));
                    break;
                case Pack:
                    //Pack,packPrice,productAmount,packId,quantity,newCustomPrice
                    orderDetailPromotionInfo.setPackPrice(new BigDecimal(split[1]));
                    orderDetailPromotionInfo.setProductAmount(Long.parseLong(split[2]));
                    orderDetailPromotionInfo.setPackQuantity(Long.parseLong(split[4]));
                    orderDetailPromotionInfo.setPackUseCoupon(Boolean.valueOf(split[5]));
                    if (split.length == 7) {
                        orderDetailPromotionInfo.setNewCustomPrice(new BigDecimal(split[6]));
                    }
                    break;
                default:
                    orderDetailPromotionInfo.setSalePrice(orderDetail.getSalePrice());
            }
            list.add(orderDetailPromotionInfo);

        }
        return list;
    }


    private PromotionType getDetailPromotion(YgOrderDetail orderDetail) {
        String remark = orderDetail.getRemark();

        if (StringUtil.isBlank(remark)) {
            return PromotionType.Ordinary;
        }
        if (remark.startsWith(PromotionType.NewCustom.name())) {
            return PromotionType.NewCustom;
        } else if (remark.startsWith(PromotionType.Pack.name())) {
            return PromotionType.Pack;
        } else if (remark.startsWith(PromotionType.Bmdism.name())) {
            return PromotionType.Bmdism;
        } else {
            return PromotionType.Ordinary;
        }

    }

    /**
     * 获取每个商品优惠券优惠的金额
     */
    private BigDecimal getDisYouHuiQuanPrce(BigDecimal youhuijuanPrice, BigDecimal excludedSpecialPrice, BigDecimal salePrice) {
        if (youhuijuanPrice.intValue() == 0) {
            return youhuijuanPrice;
        }
        return youhuijuanPrice.multiply(salePrice).divide(excludedSpecialPrice, 2, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 获取每个商品均摊的满减优惠金额
     */
    private BigDecimal getDisManJianPrice(BigDecimal manjianPrice, BigDecimal orderPrice, BigDecimal salePrice) {
        if (manjianPrice.intValue() == 0) {
            return manjianPrice;
        }
        BigDecimal price = manjianPrice.multiply(salePrice).divide(orderPrice, 2, BigDecimal.ROUND_HALF_UP);
        return price;
    }

    private void setCouponScope(OrderReturnedInfo orderReturnedInfo, YgOrder order) {
        if (order.getCouponDetailId() == null) {
            return;
        }
        YgCouponDetail detail = ygCouponDetailService.findById(order.getCouponDetailId(), order.getUserId());
        YgCoupon coupon = detail.getCoupon();
        if (SceneType.ALL.equals(coupon.getSceneType())) {
            // 全场券
            return;
        }
        List<Long> idListAtCoupon = coupon.getRelateIdList();
        List<Long> skuIdList = orderReturnedInfo.getDetailList().stream()
                .map(OrderDetailWithReturnInfo::getSkuId).collect(Collectors.toList());
        List<YgSkuInfo> skuInfoList = ygSkuService.findSkuInfoListByIds(skuIdList);
        Map<Long, List<OrderDetailWithReturnInfo>> collect = orderReturnedInfo.getDetailList().stream()
                .collect(Collectors.groupingBy(OrderDetailWithReturnInfo::getSkuId));
        BigDecimal excludedSpecialPrice = BigDecimal.ZERO;
        for (YgSkuInfo info : skuInfoList) {
            OrderDetailWithReturnInfo returnInfo = collect.get(info.getSkuId()).get(0);
            if ((SceneType.Product.equals(coupon.getSceneType()) && idListAtCoupon.contains(info.getProductId()))
                    ||
                    (SceneType.Brand.equals(coupon.getSceneType()) && idListAtCoupon.contains(info.getBrandId()))) {
                // 符合券规则
                excludedSpecialPrice = excludedSpecialPrice.add(returnInfo.getSalePrice()
                        .multiply(BigDecimal.valueOf(returnInfo.getBuyCount())));
            } else {
                returnInfo.setSpecial(true);
            }
        }
        orderReturnedInfo.setExcludedSpecialPrice(excludedSpecialPrice);
    }
}
